<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */
declare (strict_types=1);

namespace app\shop_admin\service;

use app\index\model\OrderCommodityAttach;
use app\index\service\QrcodeService;
use app\madmin\model\Goods;
use app\madmin\model\ScrapyLog;
use app\SearchModel;
use app\shop_admin\controller\Integral;
use app\shop_admin\model\{AttachValue,
    BaseModel,
    Commodity as admin,
    Commodity,
    CommodityTotal,
    GroupCommodity,
    LiveGood,
    Merchant,
    SeckillCommodity,
    PresellCommodity,
    Sku,
    SkuInventory,
    AttachName};
use app\utils\{Addons, LiveGoods, Qrcode, RedisUtil, TrimData};
use BaconQrCode\Common\Mode;
use think\Collection;
use think\Exception;
use think\facade\Cache;
use think\facade\Db;
use think\Model;
use think\facade\Request;

class CommodityService
{

    private $user;
    private $merchantId;
    private $redis;
    const url_arr = [1 => "pages/index/index", 2 => "pages/detail/detail", 3 => "pages/mine/mine", 4 => "pages/custompage/custompage"];

    public function __construct()
    {
        global $user;
        $this->user = $user;
        $this->merchantId = $user->merchant_id;
        $this->redis = new RedisUtil();
    }


    /**
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function index()
    {
        $list = admin::where('status', 1)
            ->field('id,name')
            ->select();
        return [HTTP_SUCCESS, $list];
    }

    /**
     * @param $ids
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function findByIds($ids)
    {
        $list = admin::where(['id' => $ids])
            ->field('id,name,master')
            ->select();
        return [HTTP_SUCCESS, $list];
    }

    /**
     * 查询列表
     * @param int $page
     * @param int $size
     * @param array $data
     * @return array
     * @throws \think\db\exception\DbException
     */
    public function findSellOut(array $data, int $page = 1, int $size = 10)
    {
        $admin = admin::field(
            [
                'id',
                'merchant_id',
                'type',
                'name',
                'subtitle',
                'label',
                'master',
                'share',
                'classify_id',
                'classify_value',
                'is_limitation',
                'limitation',
                'inventory_type',
                'total',
                'sell',
                'original_price',
                'sell_price',
                'min_price',
                'max_price',
                'sort',
                'is_virtual',
                'virtual_sell',
                'deliver',
                'is_distribution',
                'distribution',
                'has_sku',
                'audit',
                'status',
                'create_time',
                'update_time'
            ]);
        $admin->with(['merchant']);
        $admin = TrimData::searchDataTrim($admin, $data, ['name', 'begin_date', 'end_date']);

        $list = $admin->where($data)
            ->where('`total` = `sell`')
            ->order('id', 'desc')
            ->paginate(['page' => $page, 'list_rows' => $size]);
        return [HTTP_SUCCESS, $list];
    }

    /**
     * 查询列表
     * @param int $page
     * @param int $size
     * @param array $data
     * @return array
     * @throws \think\db\exception\DbException
     */
    public function findAll(array $data, int $page = 1, int $size = 10)
    {
        $is_live = \request()->get('is_live');
        if ($is_live == 1) {
            #实时更新审核状态
            $t = Cache::store('redis')->get("live_goods_status_change");
            if (!$t) {
                LiveGood::changeStatus();
            }
        }
        $admin = admin::field(
            [
                'id',
                'merchant_id',
                'type',
                'name',
                'subtitle',
                'label',
                'master',
                'share',
                'classify_id',
                'classify_value',
                'is_limitation',
                'limitation',
                'inventory_type',
                'total',
                'sell',
                'original_price',
                'sell_price',
                'min_price',
                'max_price',
                'sort',
                'is_virtual',
                'virtual_sell',
                'deliver',
                'is_distribution',
                'distribution',
                'has_sku',
                'audit',
                'status',
                'create_time',
                'update_time'
            ]);
        $admin->with(['merchant', 'live_good']);
        $admin = TrimData::searchDataTrim($admin, $data, ['name', 'begin_date', 'end_date']);

        if (isset($data['classify_id'])) {
            $admin = $admin->whereRaw("FIND_IN_SET('" . $data['classify_id'] . "',classify_id)");
        } else {
            $admin = $admin->where($data);
        }
        $list = $admin
            ->order('sort DESC,create_time DESC')
            ->paginate(['page' => $page, 'list_rows' => $size]);

        foreach ($list as $key => $value) {
            if (checkAddons(24)) {
                $gc = GroupCommodity::where('commodity_id', $value['id'])
                    ->field('group_id')
                    ->where('status', "in", '0,1')
                    ->find();
                $list[$key]['group'] = empty($gc) ? 0 : $gc['group_id'];
            }
            if (checkAddons(25)) {
                $sc = SeckillCommodity::where('commodity_id', $value['id'])
                    ->field('seckill_id')
                    ->where('status', "in", '0,1')
                    ->find();
                $list[$key]['seckill'] = empty($sc) ? 0 : $sc['seckill_id'];
            }
            if (checkAddons(34)) {
                $pc = PresellCommodity::where('commodity_id', $value['id'])
                    ->field('presell_id')
                    ->where('status', "in", '0,1')
                    ->find();
                $list[$key]['presell'] = empty($pc) ? 0 : $pc['presell_id'];
            }
        }

        return [HTTP_SUCCESS, $list];
    }


    public function wechataPreview($id)
    {
        $lesseeService = new LesseeService();
        list($code, $entry) = $lesseeService->entry();
        if (empty($entry) || !in_array(1, $entry)) {
            return [HTTP_NOTACCEPT, '小程序二维码生成失败'];
        }
        global $user;
        $saveUrl = './storage/qrcode/verification/';
        $name = "commodity_preview_" . hash('sha256', $user->mall_id . "_{$id}") . '.png';
        $qrcode = $this->checkWxa($saveUrl, $name, 'preview', '');
        return [HTTP_SUCCESS, $qrcode];
    }

    private function checkWxa($path, $name, $scene, $page)
    {
        if (is_file($path . $name)) {
            $qrcode = $path . $name;
        } else {
            $qrcode = new Qrcode();
            $qrcode = $qrcode->wxa($path, $name, $scene, $page, 1);
        }
        $qrcode = substr($qrcode, 1);
        return $qrcode;
    }


    /**
     * 保存数据
     * @param array $data
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function save(array $data)
    {
        if (empty($this->user->is_self)) {
            $merchant = Merchant::find($this->merchantId);
            if (!empty($merchant->is_commodity_limit)) {
                $count = admin::where(['merchant_id' => $this->merchantId])
                    ->count('id');
                if ($count > $merchant->commodity_limit)
                    throw new Exception("发布商品超过限制,请联系商城");
            }
        }

        $data['limitation_time'] = date('Y-m-d H:i:s');
        $this->changeDataForMinAndMaxPrice($data);

        $model = admin::create($data);

        if (!empty($data['has_sku'])) {
            $this->updateAttr($model, $data, 'save');

            $this->saveSkuInventoryList($model, $data['sku']);

        }

        if (!empty($data['has_attach'])) {
            global $user;
            $attach = [];
            foreach ($data['attach_value'] as $key => $value) {
                $nameAtt = [
                    'mall_id' => $user->mall_id,
                    'merchant_id' => $this->merchantId,
                    'commodity_id' => $model->id,
                    'name' => $value['name'],
                    'need' => $value['need'],
                    'toplimit' => $value['toplimit']
                ];

                $attachName = new AttachName();
                $attachNameId = $attachName->insertGetId($nameAtt);

                $att = [
                    'id' => $attachNameId,
                    'name' => $value['name'],
                    'need' => $value['need'],
                    'toplimit' => $value['toplimit']
                ];
                $ss = [];
                foreach ($value['attrValue'] as $ka => $kv) {
                    $valueAttr = [
                        'mall_id' => $user->mall_id,
                        'merchant_id' => $this->merchantId,
                        'commodity_id' => $model->id,
                        'attach_name_id' => $attachNameId,
                        'name' => $kv[0],
                        'price' => $kv[1],
                        'stock' => $kv[2]
                    ];
                    $atchValue = new AttachValue();
                    $valueId = $atchValue->insertGetId($valueAttr);
                    array_push($ss, [$valueId, $kv[0], $kv[1], $kv[2]]);
                }
                $att['attrValue'] = $ss;
                array_push($attach, $att);
            }
            admin::update(['attach_value' => $attach], ['id' => $model->id]);
        }

        CommodityTotal::create(['commodity_id' => $model->id]);

        return [HTTP_CREATED, $model];
    }


    /**
     * 读取一条数据
     * @param int $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function read(int $id)
    {
        $model = admin::find($id);
        if (!empty($model->has_sku))
            $model = admin::with(['sku', 'sku.inventory'])->find($id);
        $model = $model->toArray();
        if (!empty($model['attach_value'])) {
            foreach ($model['attach_value'] as $key => $value) {
                $av = [];
                foreach ($value['attrValue'] as $ka => $kv) {
                    $atr = AttachValue::find($kv[0]);
                    $sellAtr = OrderCommodityAttach::where([
                        'attach_id' => $kv[0],
                        'status' => 1,
                    ])->sum('num');
                    array_push($av, array_merge($kv, [$atr['stock'] - $sellAtr]));
                }
                $model['attach_value'][$key]['attrValue'] = $av;
            }
        }

        return [HTTP_SUCCESS, $model];
    }


    /**
     * 更新数据
     * @param int $id
     * @param array $data
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function update(int $id, array $data)
    {
        $update_time = $data['update_time'];
        unset($data['update_time'], $data['sell']);

        $model = admin::where(['update_time' => $update_time])->lock(true)->find($id);

        if (empty($model)) {
            return [HTTP_CREATED, 0];
        }

        if (isset($data['is_limitation']) &&
            empty($model->is_limitation) &&
            $model->is_limitation != $data['is_limitation']) {
            $data['limitation_time'] = date('Y-m-d H:i:s');
        }

        if ($model->sell > $data['total']) {
            throw new Exception("数量有误", HTTP_FORBIDDEN);
        }

        $modelStatus = $model->status;

        $data['status'] = 0;

        $total = $this->changeDataForMinAndMaxPrice($data);

        if ($data['has_sku'] == 1) {
            $data['total'] = bcadd((string)$total, (string)$model->sell, 0);
        }

        if (!empty($data['has_sku'])) {
            $this->updateAttr($model, $data, 'update');
        }

        if (empty($data['has_sku'])) {
            $this->updateNullSkuAndStore($id, $data);
        } else {
            $this->updateHasSkuAndNullStore($model, $data);
        }

        if (!empty($modelStatus)) {
            list($code, $shelf) = $this->shelf(['status' => $modelStatus, 'ids' => [$id]]);
            if ($code != HTTP_CREATED || empty($shelf["successIds"]))
                throw new Exception("下架编辑重新审核", HTTP_NOTACCEPT);
        }
        // 更新附加属性
        if (empty($data['has_attach'])) {
            AttachName::where('commodity_id', $model->id)->delete();
            AttachValue::where('commodity_id', $model->id)->delete();
        } else {
            $attachData = $data['attach_value'];
            global $user;
            $attach = [];

            $nameIdArr = array_column(AttachName::field('id')->where('commodity_id', $model->id)->select()->toArray(), "id");
            foreach ($attachData as $key => $value) {

                if (isset($value['id'])) {
                    $nameIdArr = array_diff($nameIdArr, [$value['id']]);

                    $att = [
                        'name' => $value['name'],
                        'need' => $value['need'],
                        'toplimit' => $value['toplimit']
                    ];
                    AttachName::update($att, ['id' => $value['id']]);
                    $att['id'] = $value['id'];

                    $ss = [];
                    $valueIdArr = array_column(AttachValue::field('id')->where('attach_name_id', $value['id'])->select()->toArray(), "id");
                    $valueArr = $value['attrValue'];
                    foreach ($valueArr as $vakey => $vavalue) {
                        if (count($vavalue) == 4) {
                            $valueIdArr = array_diff($valueIdArr, [$vavalue[0]]);
                            $vAtt = [
                                'name' => $vavalue[1],
                                'price' => $vavalue[2],
                                'stock' => $vavalue[3]
                            ];
                            AttachValue::update($vAtt, ['id' => $vavalue[0]]);
                            array_push($ss, [$vavalue[0], $vavalue[1], $vavalue[2], $vavalue[3]]);
                        } else {
                            $valueAttr = [
                                'mall_id' => $user->mall_id,
                                'merchant_id' => $this->merchantId,
                                'commodity_id' => $model->id,
                                'attach_name_id' => $value['id'],
                                'name' => $vavalue[0],
                                'price' => $vavalue[1],
                                'stock' => $vavalue[2]
                            ];
                            $atchValue = new AttachValue();
                            $valueId = $atchValue->insertGetId($valueAttr);
                            array_push($ss, [$valueId, $vavalue[0], $vavalue[1], $vavalue[2]]);
                        }
                    }
                    $att['attrValue'] = $ss;
                    array_push($attach, $att);
                    if (count($valueIdArr) > 0) {
                        // 删除多余数据
                        AttachValue::where('id', 'IN', $valueIdArr)->delete();
                    }
                } else {
                    $nameAtt = [
                        'mall_id' => $user->mall_id,
                        'merchant_id' => $this->merchantId,
                        'commodity_id' => $model->id,
                        'name' => $value['name'],
                        'need' => $value['need'],
                        'toplimit' => $value['toplimit']
                    ];

                    $attachName = new AttachName();
                    $attachNameId = $attachName->insertGetId($nameAtt);

                    $att = [
                        'id' => $attachNameId,
                        'name' => $value['name'],
                        'need' => $value['need'],
                        'toplimit' => $value['toplimit']
                    ];
                    $ss = [];
                    foreach ($value['attrValue'] as $ka => $kv) {
                        $valueAttr = [
                            'mall_id' => $user->mall_id,
                            'merchant_id' => $this->merchantId,
                            'commodity_id' => $model->id,
                            'attach_name_id' => $attachNameId,
                            'name' => $kv[0],
                            'price' => $kv[1],
                            'stock' => $kv[2]
                        ];
                        $atchValue = new AttachValue();
                        $valueId = $atchValue->insertGetId($valueAttr);
                        array_push($ss, [$valueId, $kv[0], $kv[1], $kv[2]]);
                    }
                    $att['attrValue'] = $ss;
                    array_push($attach, $att);
                }

            }
            if (count($nameIdArr) > 0) {
                // 删除多余数据
                AttachName::where('id', 'IN', $valueIdArr)->delete();
                AttachValue::where('attach_name_id', 'IN', $nameIdArr)->delete();
            }
            admin::update(['attach_value' => $attach], ['id' => $model->id]);
        }

        return [HTTP_CREATED, 1];
    }

    public function reaudit($id)
    {
        $model = admin::lock(true)->find($id);
        if (empty($model)) {
            return [HTTP_SUCCESS, "商品不存在"];
        }

        if ($model->audit == 0) {
            return [HTTP_SUCCESS, "商品已发起审核"];
        }

        if ($model->audit == 1) {
            return [HTTP_SUCCESS, "商品已通过审核,无需重新审核"];
        }

        $model->audit = 0;
        $model->audit_remark = null;
        $model->save();
        return [HTTP_CREATED, $model];

    }

    /**
     * 修改库存
     * @param int $id
     * @param array $data
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function inventory(int $id, array $data)
    {

        if ($data['type'] == 0) {
            $commodity = admin::where(['id' => $id])->lock(true)->find();
            if ($commodity->sell > $data['data']['total']) {
                throw new Exception("数量有误", HTTP_FORBIDDEN);
            }
            $updateData = [
                "sell_price" => $data['data']['sell_price'],
                "total" => $data['data']["total"],
                'min_price' => $data['data']['sell_price'],
                'max_price' => $data['data']['sell_price']
            ];
            admin::update($updateData, ['id' => $id]);
        } elseif ($data['type'] == 1) {

            $commodity = admin::where(['id' => $id])->lock(true)->find();
            $inventory = array_sum(array_column($data['inventory_data'], 'total'));
            $inventory = bcadd((string)$inventory, (string)$commodity->sell);

            foreach ($data['inventory_data'] as $v) {
                $skuInventory = SkuInventory::where(['id' => $v['id']])->lock(true)->find();
                if ($skuInventory->sell > $v['total']) {
                    throw new Exception("数量有误", HTTP_FORBIDDEN);
                }
                $inventory = bcsub((string)$inventory, (string)$skuInventory->sell);
                SkuInventory::update($v, ['id' => $v['id']]);
            }

            $sellPriceList = array_column($data['inventory_data'], 'sell_price');
            sort($sellPriceList);
            $minPirce = pos($sellPriceList);
            end($sellPriceList);
            $maxPrice = pos($sellPriceList);
            $commodityData = ['total' => $inventory, 'sell_price' => $minPirce, 'min_price' => $minPirce, 'max_price' => $maxPrice];
            admin::update($commodityData, ['id' => $id]);
        }

        if (!empty($commodity->status)) {
            list($code, $shelf) = $this->shelf(['status' => 1, 'ids' => [$id]]);
            if ($code != HTTP_CREATED || empty($shelf["successIds"]))
                throw new Exception("修改失败", HTTP_SERVERERROR);
        }

        return [HTTP_CREATED, 1];
    }

    /**
     * 上下架
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function shelf(array $data)
    {
        $status = $data['status'];
        $ids = $data['ids'];
        if (empty($status)) {
            admin::where('id', 'in', $ids)->update(['status' => 0]);
            foreach ($ids as $id) {
//                $this->redis->delete(checkRedisKey("COMMODITY:" . $id));
//                $this->deleteInventory("COMMODITY:" . $id . ":*SELL");
            }
            return [HTTP_CREATED, ['successIds' => $ids]];
        }

        if ($status == 1) {
            $noAuditIds = [];
            $successIds = [];
            $noSuccessIds = [];
            foreach ($ids as $id) {
                $model = admin::find($id);
                if (empty($model->audit)) {
                    $noAuditIds[] = $id;
                    continue;
                }
                if ($this->redis->exists(checkRedisKey('LOCK:' . $id))) {
                    $noSuccessIds[] = $id;
                    continue;
                }
                $this->redis->lPush(checkRedisKey('LOCK:' . $id));

                $this->commodityToRedis($model);
                $this->inventoryToRedis($model);
                $this->redis->del(checkRedisKey('LOCK:' . $id));
                $successIds[] = $id;
                $model->status = $status;
                $model->save();
            }

            return [HTTP_CREATED, ['noAuditIds' => $noAuditIds, 'successIds' => $successIds, 'noSuccessIds' => $noSuccessIds]];
        }
        return [HTTP_NOTACCEPT, "提交参数有误"];
    }

    /**
     * @param $id
     * @return int
     */
    public function delete(array $ids)
    {
        foreach ($ids as $id) {
            $this->redis->delete(checkRedisKey("COMMODITY:" . $id));
            $this->deleteInventory("COMMODITY:" . $id . ":*SELL");
        }
        admin::destroy($ids);
        return HTTP_NOCONTEND;
    }

    /**
     * 添加商品部分数据到缓存
     * @param $id
     * @param $data
     */
    private function commodityToRedis(Model $model)
    {
        $dataToRedis['name'] = $model->name;
        $dataToRedis['master'] = $model->master;
        $dataToRedis['sell_price'] = $model->sell_price;
        $dataToRedis['is_limitation'] = $model->is_limitation ?? 0;
        $dataToRedis['limitation'] = $model->limitation;
        $dataToRedis['limitation_time'] = $model->limitation_time;
        $dataToRedis['limitation_type'] = $model->limitation_type;
        $dataToRedis['inventory_type'] = $model->inventory_type;
        $dataToRedis['deliver'] = $model->deliver;
        $dataToRedis['ft_type'] = $model->ft_type;
        $dataToRedis['ft_id'] = $model->ft_id;
        $dataToRedis['ft_price'] = $model->ft_price;
        $dataToRedis['is_distribution'] = $model->is_distribution;
        $dataToRedis['is_base_distribution'] = $model->is_base_distribution;
        $dataToRedis['merchant_id'] = $model->merchant_id;
        $dataToRedis['is_self'] = $model->merchant->is_self;
        $dataToRedis['distribution'] = $model->distribution;
        $dataToRedis['has_sku'] = $model->has_sku;
        $dataToRedis['store'] = $model->merchant->store ? $model->merchant->store->toArray() : [];
        $dataToRedis['sku'] = $model->sku ? $model->sku->toArray() : [];
        $dataToRedis['integral'] = $model->integral;
        $dataToRedis['is_integral'] = $model->is_integral;
        $dataToRedis['integral_deduction'] = $model->integral_deduction;
        $dataToRedis['integral_maximum'] = $model->integral_maximum;
        $dataToRedis['has_attach'] = $model->has_attach;
        $dataToRedis['attach_value'] = $model->attach_value;

        $this->redis->set(checkRedisKey("COMMODITY:" . $model->id), json_encode($dataToRedis));
    }

    private function deleteInventory(string $pattern)
    {
        $keys = $this->redis->keys(checkRedisKey($pattern));
        $this->redis->del($keys);
    }

    /**
     * 添加商品库存到缓存
     * @param Model $model
     * @param array $data
     */
    private function inventoryToRedis(Model $model)
    {
        $this->deleteInventory("COMMODITY:" . $model->id . ":*SELL");
        if (empty($model->has_sku)) {
            $key = "COMMODITY:" . $model->id . ":SELL";
            $this->sellPriceAndTotalToRedis($key, (int)bcsub((string)$model->total, (string)$model->sell), ['sell_price' => $model->sell_price, 'level_price' => $model->level_price]);
        } else {
            foreach ($model->sku as $v) {
                if (1 == $v->status) continue;
                $key = "COMMODITY:" . $model->id . ":SKU:" . $v->id . ":SELL";
                $this->sellPriceAndTotalToRedis($key, (int)bcsub((string)$v->inventory->total, (string)$v->inventory->sell), ['sell_price' => $v->inventory->sell_price, 'level_price' => $v->inventory->level_price]);
            }
        }
    }

    /**
     * 添加库存分属性到缓存
     * @param $key
     * @param $total
     * @param $value
     */
    private function sellPriceAndTotalToRedis($key, $total, $value)
    {
        $data = [];
        $data = array_pad($data, $total, json_encode($value));
        $this->redis->lPush(checkRedisKey($key), ...$data);
    }

    /**
     * 设置数据内的最大最小价
     * @param $data
     * @return mixed
     */
    public function changeDataForMinAndMaxPrice(&$data)
    {
        if (empty($data['has_sku'])) {
            $data['min_price'] = $data['max_price'] = $data['sell_price'];
        } else {
            $data['sku'] = is_string($data['sku']) ? json_decode($data['sku'], true) : $data['sku'];
            $data['sku_value'] = is_string($data['sku_value']) ? json_decode($data['sku_value'], true) : $data['sku_value'];
            list($data['sell_price'], $data['max_price'], $data['original_price'], $data['total'], $data['weight']) = self::getMinAndMaxPriceByInventory($data['sku'], 'inventory');
            $data['min_price'] = $data['sell_price'];
        }
        return $data['total'];
    }

    /**
     * 获取sku内的最大最小价
     * @param $sku
     * @param $flag
     * @return array
     */
    public function getMinAndMaxPriceByInventory($sku, $flag)
    {
        $inventoryList = array_column($sku, $flag);
        $total = array_sum(array_column($inventoryList, 'total'));

        $sellPrice = [];
        foreach ($inventoryList as $k => $v) {
            $sellPrice = array_merge($sellPrice, [$k => $v['sell_price']]);
        }
        asort($sellPrice);
        $minPirce = pos($sellPrice);
        $originalPrice = $inventoryList[key($sellPrice)]['original_price'];
        $weight = $sku[key($sellPrice)]['weight'];
        end($sellPrice);
        $maxPrice = pos($sellPrice);
        return [$minPirce, $maxPrice, $originalPrice, $total, $weight];
    }

    /**
     * 更新模型内的sku
     * @param Model $model
     * @param $data
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateAttr(Model $model, &$data, string $method)
    {

        $attrService = new AttrService();
        $attrService->$method((int)$model->id, $data['sku_value']);
        $attrList = $attrService->index($model->id);

        $model->sku_value = $attrList;
        $model->save();

        $data['sku_value'] = (!$attrList) ? [] : $attrList->toArray();
        $attrArr = $this->clearSkuAttr($attrList);

        $this->clearSku($attrArr, $data['sku']);

    }

    /**
     * 整理skuAttr
     * @param Collection $data
     * @return array
     */
    public function clearSkuAttr(Collection $data)
    {
        $ret = [];
        $data = $data->toArray();
        foreach ($data as $k => $v) {
            $ret[$v['name']]['id'] = $v['id'];
            foreach ($v['attrValue'] as $i => $j) {
                $ret[$v['name']][$j['value']] = $j['id'];
            }
        }
        return $ret;
    }

    /**
     * 整理sku->pvs
     * @param $attrArr
     * @param $skuArr
     */
    public function clearSku($attrArr, &$skuArr)
    {

        foreach ($skuArr as $k => $v) {
            $skuArr[$k]['pvs_value'] = $v['pvs'];
            $pvsValue = '';
            $skuList = explode(',', $v['pvs']);

            $x = 1;
            foreach ($skuList as $j) {
                $skuAttr = explode(':', $j);

                $skuAttr[1] = str_replace("--", "", $skuAttr[1]);


                $pvsValue .= $attrArr[$skuAttr[0]]['id'] . ":" . $attrArr[$skuAttr[0]][$skuAttr[1]];
                if ($x != sizeof($skuList)) {
                    $pvsValue .= ",";
                    $x++;
                }
            }
            $skuArr[$k]['pvs'] = $pvsValue;
        }

    }


    /**
     * 添加SkuInventoryList
     * @param Model $model
     * @param array $skuList
     */
    private function saveSkuInventoryList(Model $model, array $skuList)
    {
        foreach ($skuList as $k => $v) {
            $this->saveSkuInventory($model, $v);
        }
    }

    /**
     * 添加SkuInventory
     * @param Model $model
     * @param array $skuData
     */
    private function saveSkuInventory(Model $model, array $skuData)
    {
        $sku = new Sku();
        $skuData['commodity_id'] = $model->id;
        $sku->inventory = new SkuInventory($skuData['inventory']);

        $sku->together(['inventory'])->save($skuData);

    }

    /**
     * 添加StoreSkuInventory
     * @param Model $model
     * @param array $skuData
     */
    private function saveStoreSkuInventory(Model $model, array $skuData)
    {
        $skuData['commodity_id'] = $model->id;
        $sku = Sku::create($skuData);
        $sku->storeSkuInventory()->saveAll($skuData['store_sku_inventory']);
    }

    /**
     * 修改NullSkuAndStore
     * @param $id
     * @param $data
     */
    private function updateNullSkuAndStore($id, $data)
    {
        Sku::where('commodity_id', $id)->delete();
        admin::update($data, ['id' => $id]);
    }

    /**
     * 整合id
     * @param $model
     * @param $field
     * @param $id
     * @param $data
     * @return array
     */
    private function idDiffAndIntersect($model, $field, $id, $data)
    {
        $oldIds = $model::where($field, $id)->column('id');
        $newIds = array_column($data, 'id');
        $arrayDiffAndIntersect = arrayDiffAndIntersect($oldIds, $newIds);
        return $arrayDiffAndIntersect;
    }

    /**
     * 修改HasSkuAndNullStore
     * @param Model $model
     * @param array $data
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws Exception
     */
    private function updateHasSkuAndNullStore(Model $model, array $data)
    {
        if (!empty($model->has_sku)) {
            list($diffIds, $intersectIds) = $this->idDiffAndIntersect(Sku::class, 'commodity_id', $model->id, $data['sku']);
            Sku::destroy($diffIds);
            foreach ($data['sku'] as $k => $v) {
                if (!isset($v['id'])) {
                    $this->saveSkuInventory($model, $v);
                } elseif (in_array($v['id'], $intersectIds)) {
                    $sku = Sku::find($v['id']);
                    if ($sku->inventory->sell > $v['inventory']['total']) {
                        throw new Exception("数量有误", HTTP_FORBIDDEN);
                    }
                    $data['total'] = bcsub((string)$data['total'], (string)$sku->inventory->sell);
                    unset($v['inventory']['sell']);
                    $sku->save($v);
                    SkuInventory::update($v['inventory'], ['id' => $v['inventory']['id']]);
                }
            }
        } elseif (empty($model->has_sku)) {
            $this->saveSkuInventoryList($model, $data['sku']);
        }
        $model->save($data);
    }

    /**商品预览
     * @param string $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function shop_preview(string $id)
    {

        $user_type = \request()->get('user_type', 3);
        global $user;
        $base_url = Request::domain() . "/h5/#/";
        $lj = self::url_arr[2];
        $sid = admin::where('status', 1)->order('id desc')->field('id')->find($id);
        if ($user_type == 1) {
            //todo 微信小程序
            global $baseIn;
            global $user;
            global $m_id;
            $m_id = $user->mall_id;
            $baseIn = "wechata";
            $path = "";
//            $page="pages/index/index"; #首页
//            $page="pages/mine/mine"; #个人中心
            $scene = "id={$sid['id']};mall_id={$m_id}";
            try {
                $service = new QrcodeService();
                list($code, $msg) = $service->qrcode($path, "", $scene, $lj);
                $data['link'] = \request()->domain() . $msg;
            } catch (\Exception $e) {
                return [HTTP_NOTACCEPT, $e->getMessage()];
            }

        } else {
            $str = $base_url . $lj . "?id=" . $sid['id'] . "&mall_id=" . $user->mall_id;
            $data = [
                'link' => $str
            ];
        }

        return [HTTP_SUCCESS, $data];
    }

    /**
     * 查询列表
     * @param int $page
     * @param int $size
     * @param array $data
     * @return array
     * @throws \think\db\exception\DbException
     */
    public function scrapyLogList($data, int $page = 1, int $size = 10)
    {


        $where = [];

        if (isset($data['status']) && is_numeric($data['status'])) {
            $where['status'] = $data['status'];
        }
        $admin = ScrapyLog::where($where);
        $list = $admin
            ->order('create_time DESC')
            ->paginate(['page' => $page, 'list_rows' => $size]);

        foreach ($list as $item => $value) {
            $value->desc = json_decode($value->desc, true);
        }


        return [HTTP_SUCCESS, $list];
    }

    public function reset()
    {
        $all = Goods::where(['status' => 1])->select();

        foreach ($all as $model) {
            $this->resetGoodsRedis($model);
            if (empty($model->has_sku)) {
                $key = "COMMODITY:" . $model->id . ":SELL";
                $this->resetinventoryRedis($model, $key, (int)bcsub((string)$model->total, (string)$model->sell), ['sell_price' => $model->sell_price, 'level_price' => $model->level_price]);
            } else {
                foreach ($model->sku as $v) {
                    if (1 == $v->status) continue;
                    $key = "COMMODITY:" . $model->id . ":SKU:" . $v->id . ":SELL";
                    $this->resetinventoryRedis($model, $key, (int)bcsub((string)$v->inventory->total, (string)$v->inventory->sell), ['sell_price' => $v->inventory->sell_price, 'level_price' => $v->inventory->level_price]);
                }
            }
        }
    }


    private function resetinventoryRedis($model, $key, $total, $value)
    {
        $key = "MALL:" . $model->mall_id . ":" . $key;
        $data = [];
        $data = array_pad($data, $total, json_encode($value));
        $this->redis->lPush($key, ...$data);
    }

    /**
     * 重置商品缓存
     * @param $key
     * @param $total
     * @param $value
     */
    private function resetGoodsRedis($model)
    {

        $dataToRedis['name'] = $model->name;
        $dataToRedis['master'] = $model->master;
        $dataToRedis['sell_price'] = $model->sell_price;
        $dataToRedis['is_limitation'] = $model->is_limitation ?? 0;
        $dataToRedis['limitation'] = $model->limitation;
        $dataToRedis['limitation_time'] = $model->limitation_time;
        $dataToRedis['limitation_type'] = $model->limitation_type;
        $dataToRedis['inventory_type'] = $model->inventory_type;
        $dataToRedis['deliver'] = $model->deliver;
        $dataToRedis['ft_type'] = $model->ft_type;
        $dataToRedis['ft_id'] = $model->ft_id;
        $dataToRedis['ft_price'] = $model->ft_price;
        $dataToRedis['is_distribution'] = $model->is_distribution;
        $dataToRedis['is_base_distribution'] = $model->is_base_distribution;
        $dataToRedis['merchant_id'] = $model->merchant_id;
        $dataToRedis['is_self'] = $model->merchant->is_self ?? 0;
        $dataToRedis['distribution'] = $model->distribution;
        $dataToRedis['has_sku'] = $model->has_sku;
        $dataToRedis['store'] = !empty($model->merchant) ? ($model->merchant->store ? $model->merchant->store->toArray() : []) : [];
        $dataToRedis['sku'] = $model->sku ? $model->sku->toArray() : [];
        $dataToRedis['integral'] = $model->integral;
        $dataToRedis['is_integral'] = $model->is_integral;
        $dataToRedis['integral_deduction'] = $model->integral_deduction;
        $dataToRedis['integral_maximum'] = $model->integral_maximum;
        $dataToRedis['has_attach'] = $model->has_attach;
        $dataToRedis['attach_value'] = $model->attach_value;

        $this->redis->set("MALL:" . $model->mall_id . ":" . "COMMODITY:" . $model->id, json_encode($dataToRedis));


        $pattern = "MALL:" . $model->mall_id . ":" . "COMMODITY:" . $model->id . ":*SELL";
        $keys = $this->redis->keys($pattern);

        $this->redis->del($keys);

    }
}
